#include "kongzhi_impl1.h"

void Cunchuti_kongzhi::add_cunchuti(const string &path) {
	unique_lock<mutex> lock_cu(MUTEX_CU);
	unique_lock<mutex> lock_bitview(MUTEX_BITVIEW);
	struct stat f_stat;
	int file;											//文件描述符
	for (int i = 0; i < (int) CUNCHUTI_TABLE.size(); ++i) {
		if (string(CUNCHUTI_TABLE[i].get_file_path()).compare(path) == 0)
			throw "存儲體文件已存在";
	}
	if ((file = open(path.c_str(), O_RDONLY) == -1))
		throw "存儲體文件打開失敗";
	if (stat(path.c_str(), &f_stat) == -1)
		throw "获取stat出问题";
	if (!S_ISREG(f_stat.st_mode))
		throw "文件非普通文件";
	unsigned long yu = 0;
	if (BITVIEW_YU != 0) yu = 64 - BITVIEW_YU;
	unsigned long kuai_sum = f_stat.st_size / 4096 - yu;	//總塊數減去bit_view_yu中空餘的空間後有多少個塊（占用位圖的位數）
	unsigned long bit_view = kuai_sum / 64;			//還需添加進位圖（vector<long>）的元素個數
	BITVIEW_YU = bit_view % 64;
	if (BITVIEW_YU != 0) {										//若餘數不為0就多加一個元素
		++bit_view;
	}
	Cunchuti_impl1 pcunchuti;
	string sname(path, path.find_last_of("/") + 1);
	pcunchuti.set_file_path(path);
	pcunchuti.set_file_name(sname);
	pcunchuti.set_size((kuai_sum + yu) * 4096);
	pcunchuti.set_creat_time(time(NULL));
	pcunchuti.set_if_local(true);
	CUNCHUTI_TABLE.push_back(pcunchuti);
	Serializable<Cunchuti>()(pcunchuti, string(CUNCHUTI_TABLE_FILE),ios::binary | ios::app);
	CUNCHUTI_SIZE = get_all_size();
	CUNCHUTI_SIZE += (kuai_sum + yu) * 4096;
	ser_all_size();
	CUNCHUTI_BITVIEW.insert(CUNCHUTI_BITVIEW.end(), bit_view, 0);
	for (unsigned long i : CUNCHUTI_BITVIEW)
		Serializable<unsigned long>()(i, string(CUNCHUTI_BITVIEW_FILE),
				ios::binary | ios::app);
	Serializable<unsigned long>()(BITVIEW_YU, string(CUNCHUTI_BITVIEW_YU),
			ios::binary);
	close(file);
}

void Cunchuti_kongzhi::rem_cunchuti(string &path) {

}

void Cunchuti_kongzhi::charu(char *str, unsigned long kuai_num, int size) {
	int kuai_sum = size / 4;									//所需塊總數
	size *= 1024;										//size單位(kb)轉換為字節(byte)
	CUNCHUTI_USEDSIZE = get_used_size();
	CUNCHUTI_USEDSIZE += size;
	num_add na = dizhizhuanhuan(kuai_num);					//轉換後的地址存放在na中
	if (CUNCHUTI_TABLE[na.cunchuti_num].get_if_local()) {
		FILE *file = fopen(CUNCHUTI_TABLE[na.cunchuti_num].get_file_path(),
				"r+");
		fseek(file, na.cunchuti_add, SEEK_SET);
		fwrite(str, size, 1, file);
		fclose(file);
	}
	for (int i = 0; i < kuai_sum; ++i) {
		bitview_fanzhuan(kuai_num + i, 1);
	}
	ser_used_size();
}

char* Cunchuti_kongzhi::quchu(unsigned long kuai_num, int size) {
	size *= 1024;										//size單位(kb)轉換為字節(byte)
	char *buf = new char[size] { 0 };									//讀取緩衝數組
	num_add na = dizhizhuanhuan(kuai_num);					//轉換後的地址存放在na中
	if (CUNCHUTI_TABLE[na.cunchuti_num].get_if_local()) {//判斷kuai_num對應的存儲體是否在本地
		ifstream infile(CUNCHUTI_TABLE[na.cunchuti_num].get_file_path(),
				ios::in | ios::binary);
		infile.seekg(na.cunchuti_add);
		infile.read(buf, size);
		infile.close();
	}
	return buf;
}

unsigned long Cunchuti_kongzhi::get_firstkuai_num(int size) {
	unique_lock<mutex> lock(MUTEX_BITVIEW);
	int if_size = 0;
	unsigned long start_i = 0;//if_size表示是否計數到size大小，start_i表示符合size大小連續存儲空間的起始地址
	for (unsigned long i = 0; i < CUNCHUTI_BITVIEW.size(); ++i) {		//遍歷位示圖
		for (int j = 0; j < 64; ++j) {				//long占8字節64bit，每個元素遍歷64次
			unsigned long wei = 1;									//輔助變量
			wei <<= j;
			if ((wei & CUNCHUTI_BITVIEW[i]) == 0) {			//按位與，如果結果為0表示該塊未被使用
				if (if_size == 0) {
					start_i = i * 64 + j;
				}
				++if_size;
			} else {
				if_size = 0;
			}
			if (if_size == size) {
				return start_i;
			}
		}
	}
	throw "存儲空間已滿";

}

num_add Cunchuti_kongzhi::dizhizhuanhuan(unsigned long kuai_num) {
	unsigned long add_pianyi = 0;							//地址偏移量，為存儲體size之和
	unsigned long add_sum = 0;
	for (int i = 0; i < (int) CUNCHUTI_TABLE.size(); ++i) {		//遍歷存儲體表，完成地址轉換
		add_sum += CUNCHUTI_TABLE[i].get_size() / 4096;
		if (kuai_num < add_sum) {
			num_add na = { i, (kuai_num - add_pianyi) * 4096 };
			return na;
		}
		add_pianyi = add_pianyi + (CUNCHUTI_TABLE[i].get_size() / 4096);
	}
	return {0};
}

void Cunchuti_kongzhi::bitview_fanzhuan(unsigned long kuai_num, char ft) {
	unique_lock<mutex> lock(MUTEX_BITVIEW);
	if (ft == 1) {
		unsigned long bit = 1;
		bit <<= kuai_num % 64;
		CUNCHUTI_BITVIEW[kuai_num / 64] |= bit;
	} else {
		unsigned long bit = (unsigned long) 0XFFFFFFFFFFFFFFFE;
		bit <<= kuai_num % 64;
		CUNCHUTI_BITVIEW[kuai_num / 64] &= bit;
		CUNCHUTI_USEDSIZE = get_used_size();
		CUNCHUTI_USEDSIZE -= 4096;
		ser_used_size();
	}
	ofstream of(string(CUNCHUTI_BITVIEW_FILE), ios::binary);
	of.close();
	for (unsigned long i : CUNCHUTI_BITVIEW)
		Serializable<unsigned long>()(i, string(CUNCHUTI_BITVIEW_FILE),
				ios::binary | ios::app);
}

unsigned long Cunchuti_kongzhi::get_all_size() {
	unsigned long s = 0;
	CUNCHUTI_SIZE = *Serializable<unsigned long>()(string(CUNCHUTI_SIZE_ALL), s);
	return CUNCHUTI_SIZE;
}

unsigned long Cunchuti_kongzhi::get_used_size() {
	unsigned long s = 0;
	CUNCHUTI_USEDSIZE = *Serializable<unsigned long>()(string(CUNCHUTI_SIZE_USED), s);
	return CUNCHUTI_USEDSIZE;
}

void Cunchuti_kongzhi::ser_all_size() {
	Serializable<unsigned long>()(CUNCHUTI_SIZE, string(CUNCHUTI_SIZE_ALL),
			ios::binary);
}

void Cunchuti_kongzhi::ser_used_size() {
	Serializable<unsigned long>()(CUNCHUTI_USEDSIZE, string(CUNCHUTI_SIZE_USED),
			ios::binary);
}

double Cunchuti_kongzhi::get_used_baifenbi(){
	unsigned long a = get_used_size();
	unsigned long b = get_all_size();
	return (double)a/b*100;
}
